package com.travel.WeChatPay;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.travel.domain.entity.Payment;
import com.travel.domain.entity.User;
import com.travel.mapper.PaymentMapper;
import com.travel.mapper.UserMapper;
import com.travel.utils.HttpServletUtils;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName com.ruoyi.pay.controller
 * @Description
 * @Author Hardy
 * @Time 2024/05/11 14:55
 */

@RestController
@Slf4j
@RequestMapping("/callback")
public class WxPayCallbackController {
    @Resource
    private PaymentMapper paymentMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RSAPublicKeyConfig rsaAutoCertificateConfig;
    private final ReentrantLock lock = new ReentrantLock();
    /**
     * 支付回调处理
     * @param request
     * @return
     */
    @PostMapping("/pay/payNotify")
    @Transactional
    public String payNotify(HttpServletRequest request) {
        log.info("------收到支付通知------");
        try {
            // 尝试获取锁
            if (!lock.tryLock()) {
                log.warn("未能获取到锁，可能有其他线程正在处理相同的订单");
                return "FAIL"; // 或者可以根据业务需求选择不同的返回值或采取其他措施
            }
            try {
                // 提取请求头信息
                String signature = request.getHeader("Wechatpay-Signature");
                String nonce = request.getHeader("Wechatpay-Nonce");
                String timestamp = request.getHeader("Wechatpay-Timestamp");
                String serial = request.getHeader("Wechatpay-Serial");
                String signType = request.getHeader("Wechatpay-Signature-Type");
                // 构造 RequestParam
                RequestParam requestParam = new RequestParam.Builder()
                        .serialNumber(serial)
                        .nonce(nonce)
                        .signature(signature)
                        .timestamp(timestamp)
                        .signType(signType)
                        .body(HttpServletUtils.getRequestBody(request))
                        .build();

                // 初始化 NotificationParser 并解析交易信息
                NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
                Transaction transaction = parser.parse(requestParam, Transaction.class);
                log.info("验签成功！-支付回调结果：{}", transaction.toString());

                // 检查交易状态
                if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
                    log.warn("内部订单号【{}】,微信支付订单号【{}】支付未成功",
                            transaction.getOutTradeNo(), transaction.getTransactionId());
                    return "FAIL";
                }
                // 加入额外的业务逻辑
                // 获取支付金额（以分为单位），并转换为元
                // 解析 attach 字段
                String attach = transaction.getAttach();
                JSONObject attachJson = JSON.parseObject(attach);
                String type = attachJson.getString("payType"); // "recharge" 或 "deduct"
                Long userId = attachJson.getLong("userId");
                BigDecimal amount = new BigDecimal(transaction.getAmount().getTotal()).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP);
                String orderId = transaction.getOutTradeNo();     // 获取订单号
                String transactionId = transaction.getTransactionId(); // 获取交易号
                String paymentStatus = transaction.getTradeState().toString(); // 获取支付状态
                Date paymentTime = new Date();              // 假设支付时间为当前时间
                Date notifyTime = new Date();               // 假设通知时间为当前时间

                // 1. 创建一个新的 Payment 对象
                Payment payment = new Payment();
                payment.setOutTradeNo(orderId);
                payment.setTransactionId(transactionId);
                payment.setAmount(amount);
                payment.setPaymentStatus(paymentStatus);
                payment.setPaymentTime(paymentTime);
                payment.setNotifyTime(notifyTime);
                payment.setUserId(userId);
                // 根据类型处理金额
                LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
                wrapper.eq(User::getId, userId);
                if ("recharge".equals(type)) {
                    // 充值：增加余额
                    wrapper.setSql("money = money + " + amount);
                    userMapper.update(null, wrapper);
                }

                // 2. 插入新的 Payment 记录到数据库
                int rowsInserted = paymentMapper.insert(payment);

                if (rowsInserted > 0) {
                    // 插入成功
                    System.out.println("New payment record created successfully.");
                } else {
                    // 插入失败
                    System.out.println("Failed to create new payment record.");
                }


                return "SUCCESS";

            } finally {
                // 确保无论如何都会解锁
                lock.unlock();
            }
        } catch (Exception e) {
            log.error("支付回调处理发生错误", e);
            return "FAIL";
        }
    }

    /**
     * 退款回调处理
     *
     * @param request
     * @return
     */
    @PostMapping("/refundNotify")

    public void refundNotify(HttpServletRequest request)   {
        try {
            log.info("------收到退款通知------");
            // 尝试获取锁
            boolean isLocked = lock.tryLock();
            if (!isLocked) {
                log.warn("未能获取到锁，可能有其他线程正在处理相同的订单");
                // 如果没有获得锁，可以选择直接返回或采取其他措施
                return; // 或者可以抛出异常、记录日志等
            }
            try {
                // 请求头Wechatpay-Signature
                String signature = request.getHeader("Wechatpay-Signature");
                // 请求头Wechatpay-nonce
                String nonce = request.getHeader("Wechatpay-Nonce");
                // 请求头Wechatpay-Timestamp
                String timestamp = request.getHeader("Wechatpay-Timestamp");
                // 微信支付证书序列号
                String serial = request.getHeader("Wechatpay-Serial");
                // 签名方式
                String signType = request.getHeader("Wechatpay-Signature-Type");
                // 构造 RequestParam
                RequestParam requestParam = new RequestParam.Builder()
                        .serialNumber(serial)
                        .nonce(nonce)
                        .signature(signature)
                        .timestamp(timestamp)
                        .signType(signType)
                        .body(HttpServletUtils.getRequestBody(request))
                        .build();

                // 初始化 NotificationParser
                NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
                // 以支付通知回调为例，验签、解密并转换成 Transaction
                log.info("验签参数：{}", requestParam);
                RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
                log.info("验签成功！-退款回调结果：{}", parse.toString());
                //parse.getRefundStatus().equals("SUCCESS");说明退款成功
                String refundStatus = parse.getRefundStatus().toString();
                log.info("getRefundStatus状态：{}", refundStatus);

                if (refundStatus.equals("SUCCESS")) {

                    log.info("成功进入退款回调，状态：{}", parse.getRefundStatus());
                    //你的业务代码

                }
            } finally {
                // 如果获得了锁，则主动释放锁
                if (isLocked) {
                    lock.unlock();
                }
            }
        } catch (Exception e) {
            log.error("退款回调失败！错误信息：{}", e.getMessage(), e); // 使用 error level 并带上堆栈信息
        }
    }
}
